// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package cgo

import (
	"sync"
	"sync/atomic"
)

// Handle提供了一种在Go和C之间传递包含Go指针
// （指向Go分配的内存的指针）的值的方法，而无需违反cgo指针传递规则。句柄是一个整数
// 值，可以表示任何Go值。句柄可以通过C传递给
// 并返回Go，Go代码可以使用句柄
// 检索原始Go值。
// 
// 保证句柄的基础类型适合整数类型
// 该类型足够大，可以容纳任何指针的位模式。句柄的零
// 值无效，因此在C API中用作哨兵
// 是安全的。例如，在移动端：
// 
// package main 
// 
// /*
// ；包括<stdint.h>
// 
// 外部无效的MyGoPrint（处理）；
// 无效myprint（uintptr\t句柄）；
// /*/
// 导入“C”
// 导入“运行时/cgo”
// 
// /导出MyGoPrint 
// 函数MyGoPrint（句柄C.UINTPG
// val:=h.Value（）（字符串）
// println（val）
// h.Delete（）
// }
// 
// func main（）{
// val:=“hello Go”
// /C.myprint（C.uintpttr___t（cgo.NewHandle（val）））
// /输出：hello Go 
// 在C端：
// 
// 用于uintptr\t 
// 
// /Go函数
// 外部无效MyGoPrint（uintptr\t句柄）；
// /
// /A C函数
// /void myprint（uintptr\t handle）{
// /MyGoPrint（handle）；
// }
type Handle uintptr

// /NewHandle返回给定值的句柄。
// 
// 句柄在程序对其调用Delete之前是有效的。句柄
// 使用资源，此包假设C代码可能保留该句柄，因此当不再需要句柄
// 时，程序必须显式调用Delete。
// 
// 预期用途是将返回的句柄传递给C代码，该代码
// 将其传递回Go，后者调用Value。
func NewHandle(v interface{}) Handle {
	h := atomic.AddUintptr(&handleIdx, 1)
	if h == 0 {
		panic("runtime/cgo: ran out of handle space")
	}

	handles.Store(h, v)
	return Handle(h)
}

// Value返回有效句柄的相关Go值。
// 
// 如果句柄无效，该方法将崩溃。
func (h Handle) Value() interface{} {
	v, ok := handles.Load(uintptr(h))
	if !ok {
		panic("runtime/cgo: misuse of an invalid Handle")
	}
	return v
}

// 删除使句柄无效。此方法只应调用一次
// 程序不再需要将句柄传递给C，并且C代码
// 不再具有句柄值的副本。
// 
// 如果句柄无效，则该方法将崩溃。
func (h Handle) Delete() {
	_, ok := handles.LoadAndDelete(uintptr(h))
	if !ok {
		panic("runtime/cgo: misuse of an invalid Handle")
	}
}

var (
	handles   = sync.Map{} // 映射[Handle]接口{}
	handleIdx uintptr      // 原子
)
